﻿#include "NpcapTest.h"

NpcapTest::NpcapTest(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
	m_adapterHandle = nullptr;
	m_bSendPackThreadExit = false;
	m_bCathPackThreadExit = false;
	on_pushButton_InitNetList_clicked();
}

NpcapTest::~NpcapTest()
{
    m_bSendPackThreadExit = true;
	//等待线程结束
    if (m_SendPackFuture._Is_ready())
        m_SendPackFuture.wait();
	m_bCathPackThreadExit = true;
    if (m_CathPackFuture._Is_ready())
        m_CathPackFuture.wait();
    if (m_adapterHandle != nullptr)
    {
        pcap_close(m_adapterHandle);
        m_adapterHandle = nullptr;
    }
}

void NpcapTest::on_pushButton_OpenNet_clicked()
{
    //关闭适配器
    if (m_adapterHandle != nullptr)
    {
        pcap_close(m_adapterHandle);
        m_adapterHandle = nullptr;
    }
    //获取网卡信息
    QList<QNetworkInterface> Interfaces = QNetworkInterface::allInterfaces();
    QNetworkInterface SelQNetworkInterface;
    for (const QNetworkInterface& selectedInterface : Interfaces)
    {
        if (selectedInterface.humanReadableName() == ui.comboBox_SelNet->currentText())
        {
            SelQNetworkInterface = selectedInterface;
            break;
        }
    }
    if (!SelQNetworkInterface.isValid())
    {
		QMessageBox::critical(this, "打开网络", "网卡不可用"); 
        return;
    }
    //网卡信息转换
    pcap_if_t* alldevs = nullptr;
    pcap_if_t* d = nullptr;
    char errbuf[PCAP_ERRBUF_SIZE * 2] = { 0 };
    int ret = pcap_findalldevs(&alldevs, errbuf);
    if (ret == -1)
    {
        if (alldevs != nullptr)
        {
            pcap_freealldevs(alldevs);	//释放适配器列表
            alldevs = nullptr;
        }
        QMessageBox::critical(this, "打开网络", "网络错误，请重启计算机！");
        return;
    }
    QList<QNetworkAddressEntry> SelNetworkAddressEntry = SelQNetworkInterface.addressEntries();
    int  SelNetworkAddressEntryNum = SelNetworkAddressEntry.size();
    //只保留IPV4
    for (int i = 0; i < SelNetworkAddressEntryNum; i++)
    {
        if (SelNetworkAddressEntry.at(i).ip().protocol() != QAbstractSocket::IPv4Protocol)
        {
            SelNetworkAddressEntry.removeAt(i);
			SelNetworkAddressEntryNum = SelNetworkAddressEntry.size();
        }
    }
    for (d = alldevs; d; d = d->next)//适配器遍历
    {
        pcap_addr_t* a = nullptr;
        for (a = d->addresses; a; a = a->next)	//IP地址遍历
        {

            QHostAddress HostAddress(a->addr);
            if (HostAddress.isNull())
                continue;
            for (int Num = 0; Num < SelNetworkAddressEntryNum; Num++)
            {
                if (HostAddress.isEqual(SelNetworkAddressEntry.at(Num).ip())) //查找相同IP的网卡
                {
                    QString s1 = HostAddress.toString();
                    QString s2 = SelNetworkAddressEntry.at(Num).ip().toString();
#define REDATIMEMS	20//pcap_open_live to_ms参数
                    m_adapterHandle = pcap_open_live(d->name, //设备名  
                        65536, // 捕捉完整的数据包  
                        PCAP_OPENFLAG_PROMISCUOUS, // 混在模式  
                        REDATIMEMS, // 读入超时  
                        errbuf // 错误缓冲  
                    );
                    break;
                }
            }
            if (m_adapterHandle)
            {
                break;
            }
        }
        if (m_adapterHandle)
        {
            break;
        }
    }
    pcap_freealldevs(alldevs);	//释放适配器列表
    /* 打开设备 */
    if (m_adapterHandle == nullptr)
    {
        QMessageBox::critical(this, "打开网络", "打开网络失败");
        return;
    }
    ui.pushButton_OpenNet->setEnabled(false);
    QMessageBox::information(this, "打开网络", "打开网络成功");
}

void NpcapTest::on_pushButton_CloseNet_clicked()
{
    ui.pushButton_OpenNet->setEnabled(true);
	//关闭适配器
	if (m_adapterHandle != nullptr)
	{
		pcap_close(m_adapterHandle);
		m_adapterHandle = nullptr;
	}
    QMessageBox::information(this, "关闭网络", "关闭网络成功");
}

void NpcapTest::on_pushButton_SendPack_clicked()
{
	//发送数据包
	if (m_adapterHandle == nullptr)
	{
		QMessageBox::critical(this, "发送数据包", "请先打开网络");
		return;
	}
	int size = ui.spinBox_SendPackLen->value();
    if (size < 12)
        size = 12;
	u_char* packet = new u_char[size];
	memset(packet, 0XFF, size);
	QString str = ui.textEdit_PackHeader->toPlainText();
    if (str.isEmpty())
    {
        const unsigned char SrcMac[] = { 0xDC ,0x05,0x04,0x03,0x02, 0x01 };
        memcpy(packet, SrcMac, sizeof(SrcMac));
        const unsigned char DesMac[] = { 0xAA ,0xBB,0xCC,0xDD,0xEE, 0xFF };
        memcpy(packet + 6, DesMac, sizeof(DesMac));
    }
    else
    {
        QByteArray byteArray = QByteArray::fromHex(str.remove("0X", Qt::CaseInsensitive).toLocal8Bit());
        memcpy(packet, byteArray.data(), byteArray.size());
    }
    int iReturn = pcap_sendpacket(m_adapterHandle, packet, size);
    if (iReturn >= 0)
    {
		QMessageBox::information(this, "发送数据包", "发送数据包成功");
    }
    else
    {
        QMessageBox::critical(this, "发送数据包", "发送数据包失败");
    }
}

void NpcapTest::on_pushButton_BeginSend_clicked()
{
    if (m_adapterHandle == nullptr)
    {
        QMessageBox::critical(this, "发送数据包", "请先打开网络");
        return;
    }
    m_bSendPackThreadExit = false;
	unsigned int uiSllepTimeMsec = ui.spinBox_SendPackTimeSpan->value();
    int size = ui.spinBox_SendPackLen->value();
    if (size < 12)
        size = 12;
    u_char* packet = new u_char[size];
    memset(packet, 0XFF, size);
    QString str = ui.textEdit_PackHeader->toPlainText();
    if (str.isEmpty())
    {
        const unsigned char SrcMac[] = { 0xDC ,0x05,0x04,0x03,0x02, 0x01 };
        memcpy(packet, SrcMac, sizeof(SrcMac));
        const unsigned char DesMac[] = { 0xAA ,0xBB,0xCC,0xDD,0xEE, 0xFF };
        memcpy(packet + 6, DesMac, sizeof(DesMac));
        m_SendPackFuture = std::async(std::launch::async, [=]() {
            while (false == m_bSendPackThreadExit)
            {
                static unsigned int uiPackID = 0;
                memcpy(packet + 12, &uiPackID, sizeof(unsigned int));
                uiPackID++;
                if (uiSllepTimeMsec > 0)
                {
                    //线程延时
                    std::this_thread::sleep_for(std::chrono::milliseconds(uiSllepTimeMsec));
                }
                int iReturn = pcap_sendpacket(m_adapterHandle, packet, size);
            }
            });
    }
    else
    {
        QByteArray byteArray = QByteArray::fromHex(str.remove("0X", Qt::CaseInsensitive).toLocal8Bit());
        memcpy(packet, byteArray.data(), byteArray.size());
        m_SendPackFuture = std::async(std::launch::async, [=]() {
            while (false == m_bSendPackThreadExit)
            {
                static unsigned int uiPackID = 0;
                memcpy(packet + 12, &uiPackID, sizeof(unsigned int));
                uiPackID++;
                if (uiSllepTimeMsec > 0)
                {
                    //线程延时
                    std::this_thread::sleep_for(std::chrono::milliseconds(uiSllepTimeMsec));
                }
                int iReturn = pcap_sendpacket(m_adapterHandle, packet, size);
            }
            });
    }
   
	ui.pushButton_BeginSend->setEnabled(false);
}

void NpcapTest::on_pushButton_StopSend_clicked()
{
	m_bSendPackThreadExit = true;
    m_SendPackFuture.wait();
    ui.pushButton_BeginSend->setEnabled(true);
    QMessageBox::information(this, "停止发送", "停止发送数据成功");
}

void NpcapTest::on_comboBox_SelNet_currentIndexChanged(const QString& text)
{
    QList<QNetworkInterface> Interfaces = QNetworkInterface::allInterfaces();
    for (const QNetworkInterface& selectedInterface : Interfaces)
    {
        if (selectedInterface.humanReadableName() == text)
        {
            // 基本信息
            QString infoText = "接口名称: " + selectedInterface.humanReadableName() + "\n";
            infoText += "MAC地址: " + selectedInterface.hardwareAddress() + "\n";

            // IP地址、子网掩码等
            QList<QNetworkAddressEntry> entries = selectedInterface.addressEntries();
            for (const QNetworkAddressEntry& entry : entries) {
                infoText += "IP地址: " + entry.ip().toString() + "\n";
                infoText += "子网掩码: " + entry.netmask().toString() + "\n";
                infoText += "广播地址: " + entry.broadcast().toString() + "\n";
            }
            ui.textBrowser_NetInfo->setPlainText(infoText);
        }
    }
}

void NpcapTest::on_pushButton_InitNetList_clicked()
{
	//获取当前网络列表
    QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
    for (const QNetworkInterface& selInterface : interfaces)
    {
        // 过滤无效接口：已启用且非虚拟接口
        if (selInterface.isValid() && (selInterface.flags() & QNetworkInterface::IsUp) && !selInterface.hardwareAddress().isEmpty()) 
        {
			ui.comboBox_SelNet->addItem(selInterface.humanReadableName());
        }
    }
}

void NpcapTest::on_pushButton_BeginRecieve_clicked()
{
    //发送数据包
    if (m_adapterHandle == nullptr)
    {
        QMessageBox::critical(this, "发送数据包", "请先打开网络");
        return;
	}
	m_bCathPackThreadExit = false;
    struct pcap_pkthdr* header = nullptr;
    const u_char* packet = nullptr;
    int iReturn = 0;
	unsigned int uiPackID = 0;
	m_CathPackFuture = std::async(std::launch::async, [&]() {
		while (false == m_bCathPackThreadExit)
		{
			iReturn = pcap_next_ex(m_adapterHandle, &header, &packet);
            if (iReturn >= 20)
            {
				unsigned int curPackID = ((unsigned int*)packet)[4];
				if (uiPackID + 1 != curPackID)
				{
					//丢包
					QString str = QString::number(uiPackID, 16).toUpper();
					str = "0X" + str;
					ui.textEdit_PackHeader->setPlainText(str);
				}
                uiPackID = curPackID;
            }
            else if (-1 == iReturn)
            {
				break;
            }
		}
		});
}

void NpcapTest::on_pushButton_StopRecieve_clicked()
{
}
